﻿define(['plugins/router',
        'plugins/dialog',
        'durandal/app', 
        'services/layout',
        'services/config',
        'services/user',
        'services/dataservice',
        'services/notifier',
        'common/menu',
        'i18n'], 
	function (router, dialog, app, L, config, user, ds, notifier, menu, i18n) {
	
		var loadingStates = ko.observable({ initial: false });
	    var isLoading = ko.computed(function() {
	        return _.reduce(loadingStates(), function(memo, val) {
	            return !!memo || !!val;
	        });
	    });
	    $.blockUI.defaults.fadeOut = 200;
	    isLoading.subscribe(function(newValue) {
	        if(newValue) {
	            $.blockUI({ message: null, baseZ: 9999, overlayCSS: {opacity: 0.3}});
	        } else {
	            $.unblockUI();
	        }
	    });
	    function setLoading(who, loading) {
	        var x = loadingStates() || {};
	        x[who] = loading;
	        if(loading) {
	            loadingStates(x);
	        } else {
	            setTimeout(function() {
	                loadingStates(x);
	            }, 200);
	        }
	    }
	
	    router.isNavigating.subscribe(function(navigating) {
	        setLoading('router', navigating);
	    });
	
	    app.on('cms:activator:activating', function(value) {
	        setLoading('activator', value);
	    });
	
	    $(document)
	        .ajaxSend(setLoading.bind(undefined, 'ajax', true))
	        .ajaxComplete(setLoading.bind(undefined, 'ajax', false));
	
	
	
	    // fade binding: replaces the visible binding with a jQuery fadeIn for
	    // smoother transitions
	    ko.bindingHandlers.fade = {
	        init: function (element, valueAccessor) {
	            var value = ko.unwrap(valueAccessor());
	            $(element).toggle(value);
	        },
	        update: function (element, valueAccessor) {
	            var value = valueAccessor();
	            ko.unwrap(value) ? $(element).fadeIn(100) : $(element).fadeOut(100);
	        }
	    };
		
		// on window resize, relayout!
	    $(window).resize(_.debounce(L.relayout.bind(L), 200));
	    
	    // react on menu refreshing (each time a new menu is fetched, updates counters on top menu)
        app.on(menu.refreshEventName, updateTopMenu);

        $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange msfullscreenchange', function(){
            shell.isInFullScreen(!shell.isInFullScreen());
        });
        
	    var routes = [
	        // Navigator left
	        { route: [''],        title: i18n.t('cms:nav.home'), moduleId: 'home/index', nav: true },
	        { route: 'demo', title: i18n.t('cms:nav.demo'), moduleId: 'home/demo',  nav: true, hash: '#demo' },
	        
	        { route: 'accounts', title: i18n.t('cms:nav.account'), moduleId: 'lists/listTemplate',  nav: true, hash: '#accounts' },
	        
	        // Navigator right
	        { route: 'login', title: i18n.t('cms:nav.login'), moduleId: 'home/login', nav: false, hash: '#login' },
	        
	        // Invisible
	        { route: 'home/notfound', title: i18n.t('cms:notfound'), moduleId: 'notfound', nav: false }
		];
        
	    var shell = {
	        router: router,
	        notifier: notifier,
	        user: user,

	        convertRouteToHash: router.convertRouteToHash,

	    	logoUrl: config.app.logoUrl,
	        activate: viewActivate,
	        
	        isOlderThanIE9: olderThanIE9,
	        isIE9: isIE9,
	        toggleFullScreen: toggleFullScreen,
	        isInFullScreen: ko.observable(false),
	        // business alerts animation at top of page
	        showAlert: showAlert,
	        hideAlert: hideAlert,
	        search: search,
	        logout: logout 
	    };
	    
	    // hides menus (standaloneForm e.g.)
	    shell.hideInterface = ko.computed(function () {
	        if (router.activeInstruction()) {
	            return router.activeInstruction().config.hideInterface;
	        } else {
	            return false;
	        }
	    });
	
	    // current page is a list template, meaning it has a left menu.
	    shell.isListTemplate = ko.computed(function() {
	        if(router.activeInstruction()) {
	            return !!router.activeInstruction().config.opusId;
	        } else {
	            return false;
	        }
	    });
	
	    return shell;
	    
	    function logout() {
	    	ds.logout();
	    }
	    
	    function search() {
	    	//It's really easy to show a message box.
	        //You can add custom options too. Also, it returns a promise for the user's response.
	        app.showMessage('Search not yet implemented...');
	    }
	    
	    function toggleFullScreen() {
	        if(shell.isInFullScreen()) {
	            exitFullScreen();
	        } else {
	            enterFullScreen();
	        }
	    }
	
	    function enterFullScreen() {
	        var element = document.documentElement;
	
	        // Find the right method, call on correct element {
	        if(element.requestFullscreen) {
	            element.requestFullscreen();
	        } else if(element.mozRequestFullScreen) {
	            element.mozRequestFullScreen();
	        } else if(element.webkitRequestFullscreen) {
	            element.webkitRequestFullscreen();
	        } else if(element.msRequestFullscreen) {
	            element.msRequestFullscreen();
	        }
	    }
	
	    function exitFullScreen() {
	        if(document.exitFullscreen) {
	            document.exitFullscreen();
	        } else if(document.mozCancelFullScreen) {
	            document.mozCancelFullScreen();
	        } else if(document.webkitExitFullscreen) {
	            document.webkitExitFullscreen();
	        }
	    }
	
	    /**
	     * Animate alert on display
	     */
	    function showAlert(elem) {
	        if (elem.nodeType === 1) {
	            $(elem).hide().slideDown('fast', L.relayout.bind(L));
	        }
	    }
	
	    /**
	     * Animate alert when removed
	     * @param elem
	     */
	    function hideAlert(elem) {
	        if (elem.nodeType === 1) {
	            $(elem).slideUp('fast', function () {
	                $(elem).remove();
	                L.relayout();
	            });
	        }
	    }
	
	    /**
	     * is older than IE9
	     */
	    function olderThanIE9() {
	        var me = config.browser;
	        if (me && me.type) {
	            return me.type.toUpperCase() === 'MSIE' && me.version < 9;
	        }
	
	        return false;
	    }
	
	    /**
	     * browser is IE9 or older
	     */
	    function isIE9() {
	        var me = config.browser;
	        if(me && me.type) {
	            return me.type.toUpperCase() === 'MSIE' && me.version <= 9;
	        }
	
	        return false;
	    }
	
	    /**
	     * each time a menu refresh event is fired, refresh counters on navigation model
	     */
	    function updateTopMenu(topMenuData) {
	
	        if (topMenuData) {
	
	            _.each(router.navigationModel(), function (shellMenuItem) {
	
	                upgradeMenuItem(shellMenuItem);
	
	                // find refresh menu item that correspond
	                var match = topMenuData[shellMenuItem.opusId];
	
	                if (match && typeof match.mainCount !== 'undefined' && match.mainCount !== null) {
	                    shellMenuItem.hasCounters(true);
	                    shellMenuItem.mainCount(match.mainCount);
	                    shellMenuItem.secondaryCount(match.secondaryCount);
	                } else {
	                    shellMenuItem.hasCounters(false);
	                }
	
	            });
	        }
	    }
	
	    function viewActivate() {
	        L.needsRelayout();
	        return router.map(routes).buildNavigationModel()
	        	.mapUnknownRoutes('home/notfound', 'not-found')
	            .activate()
	            .then(function () {
	                _.each(router.navigationModel(), upgradeMenuItem);
	            });
	    }
	    
	    /**
	     * decorate router's navigation items with 3 new properties to track counters
	     */
	    function upgradeMenuItem(menuItem) {
	        if (!menuItem.hasCounters) {
	
	            menuItem.hasCounters = ko.observable(false);
	            menuItem.mainCount = ko.observable();
	            menuItem.secondaryCount = ko.observable();
	        }
	    }
	});